package com.cyw.common.utils;

import com.cyw.common.config.jackson.JacksonConfig;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;

import java.io.IOException;
import java.util.*;

/**
 * 封装 Jackson 序列化或反序列化工具
 * @author cyw
 */
@SuppressWarnings("all")
public class JsonUtils {
    private static final ObjectMapper MAPPER = JacksonConfig.getObjectMapper();

    public static String toJson(Object o) {
        try {
            return MAPPER.writeValueAsString(o);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    public static String toJsonIfPresent(Object o) {
        return o == null ? "" : toJson(o);
    }

    public static <T> String toJsonIfPresent(Collection<T> collection) {
        return CollectionUtils.isEmpty(collection) ? "[]" : toJson(collection);
    }

    public static <T> T toObject(String json, Class<T> clazz) {
        try {
            return MAPPER.readValue(json, clazz);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> T toObjectIfPresent(String json, Class<T> clazz) {
        try {
            return StringUtils.isNotEmpty(json) ? MAPPER.readValue(json, clazz) : null;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> T toObject(String json, TypeReference<T> typeReference) {
        try {
            return MAPPER.readValue(json, typeReference);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取泛型的Collection Type
     *
     * @param collectionClass 泛型的Collection
     * @param elementClasses  元素类
     * @return JavaType Java类型
     */
    public static JavaType getCollectionType(Class<? extends Collection> collectionClass, Class... elementClasses) {
        return MAPPER.getTypeFactory().constructParametricType(collectionClass, elementClasses);
    }

    public static <T> List<T> toList(String json, Class<? extends Collection> collectionClass, Class<T> clazz) {
        try {
            return MAPPER.readValue(json, getCollectionType(collectionClass, clazz));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> List<T> toListIfPresent(String json, Class<? extends Collection> collectionClass, Class<T> clazz) {
        try {
            return StringUtils.isEmpty(json) ?
                    Lists.newArrayList() :
                    MAPPER.readValue(json, getCollectionType(collectionClass, clazz));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> List<T> toListIfPresent(String json, Class<T> clazz) {
        return toListIfPresent(json, ArrayList.class, clazz);
    }

    public static <T> Set<T> toSetIfPresent(String json, Class<T> clazz) {
        try {
            return StringUtils.isEmpty(json) ?
                    Sets.newHashSet() :
                    MAPPER.readValue(json, getCollectionType(HashSet.class, clazz));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static Object toObject(String json, JavaType javaType) {
        try {
            return MAPPER.readValue(json, javaType);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private final static TypeReference<Map<String, String>> STRING_MAP_REFERENCE = new TypeReference<Map<String, String>>() {
    };

    private final static TypeReference<List<String>> STRING_LIST_REFERENCE = new TypeReference<List<String>>() {
    };

    public static Map<String, String> toStringMap(String json) {
        return toObject(json, STRING_MAP_REFERENCE);
    }

    public static List<String> toStringList(String json) {
        return toObject(json, STRING_LIST_REFERENCE);
    }

    public static JsonNode readJsonSingleValue(String json, String singleKey) {
        if (StringUtils.isEmpty(json) || StringUtils.isEmpty(singleKey)) {
            return null;
        }
        try {
            JsonNode node = MAPPER.readValue(json, JsonNode.class);
            return node.has(singleKey) ? node.get(singleKey) : null;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        final String json = "{\"contentType\": \"foo\", \"fooField1\": \"111\"}";
        try {
            ObjectMapper mapper = new ObjectMapper();
            JsonNode node = mapper.readValue(json, JsonNode.class);
            if (node.has("contentType")) {
                System.out.println("contentType: " + node.get("contentType"));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println(readJsonSingleValue(json, "contentType"));

    }
}
